package com.gs.netty.support.handler.channel;

import io.netty.channel.*;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.internal.TypeParameterMatcher;

/**
 * 入栈出栈处理适配器
 * @param <I>
 */
public abstract class AbstractChannelDuplexHandlerAdapter<I> extends ChannelDuplexHandler {

    private final TypeParameterMatcher Imatcher;
    private final boolean autoRelease;

    public AbstractChannelDuplexHandlerAdapter() {
        this(true);
    }

    /**
     * Returns {@code true} if the given message should be handled. If {@code false} it will be passed to the next
     * {@link ChannelInboundHandler} in the {@link ChannelPipeline}.
     */
    public boolean acceptInboundMessage(Object msg) throws Exception {
        return Imatcher.match(msg);
    }
    protected AbstractChannelDuplexHandlerAdapter(boolean autoRelease) {
        Imatcher = TypeParameterMatcher.find(this, AbstractChannelDuplexHandlerAdapter.class, "I");
        this.autoRelease = autoRelease;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

        boolean release = true;
        try {
            if (acceptInboundMessage(msg)) {
                @SuppressWarnings("unchecked")
                I imsg = (I) msg;
                channelRead0(imsg,ctx);
            } else {
                release = false;
                ctx.fireChannelRead(msg);
            }
        } finally {
            if (autoRelease && release) {
                ReferenceCountUtil.release(msg);
            }
        }
    }
    public abstract void channelRead0(I msg,ChannelHandlerContext ctx) throws Exception;
}
